package com.itheima.activiti.service.modeler.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.itheima.activiti.common.WorkflowException;
import com.itheima.activiti.dto.modeler.ModelDTO;
import com.itheima.activiti.service.modeler.ModelerService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ModelerServiceImpl implements ModelerService {

    @Autowired
    protected RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;

    private final static String MODEL_NAME = "name";
    private final static String MODEL_REVISION = "revision";
    private final static String MODEL_DESCRIPTION = "description";

    /**
     * 保存模型对象
     * @param name
     * @param key
     * @param description
     * @return
     */
    @SneakyThrows
    public String save(String name, String key, String description) {
        //新建模型对象
        Model model = repositoryService.newModel();

        //设置MetaInfo属性值，json格式
        ObjectNode metaInfo = objectMapper.createObjectNode();
        metaInfo.put(MODEL_NAME, name);
        metaInfo.put(MODEL_DESCRIPTION, description);
        metaInfo.put(MODEL_REVISION, model.getVersion());

        model.setKey(key);
        model.setName(name);
        model.setMetaInfo(metaInfo.toString());

        repositoryService.saveModel(model);

        //返回模型id
        return model.getId();
    }

    /**
     * 删除模型
     *
     * @param id 模型ID
     */
    public void delete(String id) {
        repositoryService.deleteModel(id);
    }

    /**
     * 保存前端传入的流程模型的XML
     * @param modelDTO
     */
    @Override
    public void saveXml(ModelDTO modelDTO) {
        try {
            if (StringUtils.isEmpty(modelDTO.getId())) {
                String modelId = this.save(modelDTO.getName(), modelDTO.getKey(), modelDTO.getDescription());
                modelDTO.setId(modelId);
            }

            //保存流程图的xml内容
            repositoryService.addModelEditorSource(modelDTO.getId(), modelDTO.getContent().getBytes("utf-8"));

        } catch (Exception e) {
            log.error("Error saving model", e);
            throw new WorkflowException("保存失败");
        }
    }

    @Override
    public Page<ModelDTO> page(ModelDTO modelDTO, int page, int pageSize) {
        String key = modelDTO.getKey();
        String name = modelDTO.getName();

        ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion().orderByModelName().desc();

        if (StringUtils.isNotEmpty(key)) {
            modelQuery.modelKey(key);
        }
        if (StringUtils.isNotEmpty(name)) {
            modelQuery.modelName(name);
        }
        long total = modelQuery.count();
        List<Model> list = modelQuery.listPage((page - 1) * pageSize, pageSize);

        Page<ModelDTO> pageResult = new Page(page, pageSize, total);
        List<ModelDTO> modelDTOs = list.stream().map(item -> {
            ModelDTO model = new ModelDTO();
            BeanUtils.copyProperties(item, model);
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
            query.processDefinitionKey(model.getKey());
            ProcessDefinition processDefinition = query.latestVersion().singleResult();
            if (null == processDefinition) {
                model.setVersion(null);
            } else {
                model.setVersion(processDefinition.getVersion());
                model.setProcessDefinitionId(processDefinition.getId());
                model.setProcessDefinitionKey(processDefinition.getKey());
                model.setProcessDefinitionName(processDefinition.getName());
                model.setProcessDefinitionSuspended(processDefinition.isSuspended());
            }
            return model;
        }).collect(Collectors.toList());
        pageResult.setRecords(modelDTOs);
        return pageResult;
    }

    @Override
    public String getXmlById(String id) {
        byte[] content = repositoryService.getModelEditorSource(id);
        if(content == null){    //新创建时
            return "";
        }
        else{
            return new String(content);
        }
    }
}
